package com.ibm.spatiotemp.query;

import java.util.Collection;
import java.util.HashSet;

import org.apache.log4j.Logger;

import com.ibm.spatiotemp.datamodel.datatype.Constraints;
import com.ibm.spatiotemp.datamodel.datatype.request.QueryRequest;
import com.ibm.spatiotemp.datamodel.datatype.response.Response;
import com.ibm.spatiotemp.datamodel.result.SpatioObjectResultSet;
import com.ibm.spatiotemp.processor.IndexPathFinder;
import com.ibm.spatiotemp.processor.SearcherFactory;
import com.ibm.spatiotemp.processor.SpatialSearcher;

import edu.umn.cs.spatialHadoop.core.Point;
import edu.umn.cs.spatialHadoop.core.Shape;

public class STQueryHandler {
	public static Logger logger = Logger.getLogger(STQueryHandler.class);
	/*
	 * in restful server part, we will implement real GPSDataSource as a new
	 * class
	 */
	public static String runningMode = Constraints.QUERY_LOCALMODE;

	public Response handleQuery(QueryRequest request) throws Exception {
		Shape queryshape = request.getQshape();
		if (queryshape != null) {
			/*
			 * get modidlist, if length==1, via 2ndindex, else firstly 1st idx
			 * and reubuild reqeusts by modids
			 */
			String[] modids = request.getModids();
			if (modids != null && modids.length == 1) {
				request.setIdxlayer(Constraints.IDXLAYER_SECOND);
				return handleQueryOnIndexLayer(request);
			} else {
				Response result = new Response();
				if (modids == null) {
					request.setIdxlayer(Constraints.IDXLAYER_FISRT);
					Response resp_1stidx = handleQueryOnIndexLayer(request);

					Collection<String> modidset = null;
					modidset = new HashSet<String>();

					Collection<SpatioObjectResultSet> resulsets = resp_1stidx
							.getResultset();
					for (SpatioObjectResultSet curset : resulsets) {
						modidset.addAll(curset.getMovingObjectIDs());
					}
					// GPSDataSource datasrc =
					// GPSDataSouceFactory.getGPSDataSource(request.getDatasrcid());
					for (String modid : modidset) {
						QueryRequest curreq = request.clone();
						curreq.setIdxlayer(Constraints.IDXLAYER_SECOND);
						curreq.setModids(new String[] { modid });
						result.mergeResponse(handleQueryOnIndexLayer(curreq));
					}
				} else {/* modid length > 1 */
					for (String modid : modids) {
						QueryRequest curreq = request.clone();
						curreq.setIdxlayer(Constraints.IDXLAYER_SECOND);
						curreq.setModids(new String[] { modid });
						result.mergeResponse(handleQueryOnIndexLayer(curreq));
					}
				}
				return result;
			}
		}
		logger.error("cannot be pruned by spatiotemporal index "
				+ "if query didn't contain a region");
		return null;
	}

	private Response handleQueryOnIndexLayer(QueryRequest request)
			throws Exception {
		String querytype = request.getQuerytype();
		// SpatialSearcher searcher =
		// SearcherFactory.getSearcherInstanceByRequest(request);
		IndexPathFinder finder = new IndexPathFinder();
		String[] pathset = null;
		if (request.getIdxlayer().equalsIgnoreCase(Constraints.IDXLAYER_FISRT))
			pathset = finder.find1stIndexPath(request);
		else if (request.getIdxlayer().equalsIgnoreCase(
				Constraints.IDXLAYER_SECOND))
			pathset = finder.find2ndIndexPath(request);

		Response finalres = new Response();
		if (runningMode.equals(Constraints.QUERY_LOCALMODE)) {
			for (String idxpath : pathset) {
				SpatialSearcher searcher = null;
				searcher = SearcherFactory.getSearcherInstance(idxpath);
				if(searcher!=null){
					Shape queryshape = request.getQshape();
					/* 1st layer index could be helpful in this case */
					if (querytype.equalsIgnoreCase(Constraints.QTYPE_RANGE)) {
						finalres.mergeResponse(new Response(searcher
								.Range_Query(queryshape)));
					} else if (querytype.equalsIgnoreCase(Constraints.QTYPE_KNN)) {
						int k = request.getTagAsInteger("k");
						finalres.mergeResponse(new Response(searcher.KNN_Query(
								(Point) queryshape, k)));
					} else {
						logger.error("not supported query type");
					}
					searcher.close();
				}
			}
		}
		else if(runningMode.equals(Constraints.QUERY_SPARKMODE))
		{
			logger.error("spark mode not supported now");
		}
		return finalres;
	}

}
